#include "BCIO.h"

//************************************
// Method:    	BCAVIO_PACK_Make			模拟量广播打包程序
// Programmer:  lww
// Time:		2019/2/21
// Returns:   	int							打包长度
// Parameter: 	void * Data					数据包头指针
// Parameter: 	short Head					报头
// Parameter: 	short Tail					报尾
// Parameter: 	int Limit_Len				单次数据包长度限制
// Parameter: 	short * SaveChannel_Num		存储的模块的数量
//************************************
int BCAVIO_PACK_Make(void* Data, short Head, short Tail, int Limit_Len, short* SaveChannel_Num, int* BCAVIO_CARD_Count)
{
#define MEMWRITE1(name)	MEMWRITE(name, Data);
	int _iLen = 0;
	short tmp_short;
	/*static int i = 0;*/						//< duan20200616注释
	static int j = 0;
	static int k = 0;
	void* Data1 = NULL;
	Card_Base_t* base = NULL;

	//< 报头
	MEMWRITE1(Head);

	//< 站号
	tmp_short = Station_ID;
	MEMWRITE1(tmp_short);

	//< 第三个数据存放从下一个数据开始从后数多少个字节为报尾，用于对报文的报尾进行校验，此处先保留该存储位置，稍后再对其进行存储
	Data1 = Data;
	tmp_short = 0;
	MEMWRITE1(tmp_short);
	_iLen = (int)(_iLen - sizeof(tmp_short));

	//< 第四个数据存储本次要广播的模块数量，这个数据等打包完成后最后写入，此处先保留该存储位置，稍后再对其进行存储
	MEMWRITE1(SaveChannel_Num[0]);
	_iLen = (int)(_iLen - sizeof(SaveChannel_Num[0]));

	while ((BCAVIO_CARD_Count[0] < TYP_MAX_CARD) && (_iLen < Limit_Len))
	{
		if (BCAVIO_CARD_Count[0] == TYP_SAMAIO)						//< duan0517 在此不广播软件卡件
		{ 
			BCAVIO_CARD_Count[0]++; continue;
		}

		while ((j < Card_List[BCAVIO_CARD_Count[0]].iCount) && (_iLen < Limit_Len))
		{
			base = (Card_Base_t*)SearchAt(((List_Base_t*)Card_List[BCAVIO_CARD_Count[0]].ppData[0]), j);
			if (base != NULL)
			{
				while ((k < (base->IO_Num.AI_Num + base->IO_Num.AO_Num)) && (_iLen < Limit_Len))
				{
					if (k < base->IO_Num.AI_Num)
						_iLen += BCAVIO(&(base->AIChannel[k]), &Data, SaveChannel_Num);
					else
						_iLen += BCAVIO(&(base->AOChannel[k - base->IO_Num.AI_Num]), &Data, SaveChannel_Num);
					k++;
				}
				if (k >= (base->IO_Num.AI_Num + base->IO_Num.AO_Num)) { k = 0; }
			}
			if (k == 0) { j++; }
		}
		if (j >= Card_List[BCAVIO_CARD_Count[0]].iCount) { j = 0; }
		if (j == 0) { BCAVIO_CARD_Count[0]++; }
	}
	/*if (i >= TYP_MAX_CARD) { i = 0; }*/					//< duan20200616注释

	//< 写第三个数据
	tmp_short = (short)(_iLen - sizeof(Head) - sizeof(short) + sizeof(SaveChannel_Num[0]));//< 等于目前已经计数的长度减去报头，减去站号，加上要广播模块数量数据的长度
	MEMWRITE(tmp_short, Data1);

	//< 写第四个数据
	MEMWRITE(SaveChannel_Num[0], Data1);

	//< 报尾
	MEMWRITE1(Tail);
	return _iLen;
#undef MEMWRITE1
}


//************************************
// Method:    	BCDVIO_PACK_Make			数字量广播打包程序
// Programmer:  lww
// Time:		2019/2/21
// Returns:   	int							打包长度
// Parameter: 	void * Data					数据包头指针
// Parameter: 	short Head					报头
// Parameter: 	short Tail					报尾
// Parameter: 	int Limit_Len				单次数据包长度限制
// Parameter: 	short * SaveChannel_Num		存储的模块的数量
//************************************
int BCDVIO_PACK_Make(void* Data, short Head, short Tail, int Limit_Len, short* SaveChannel_Num, int* BCDVIO_CARD_Count)
{
#define MEMWRITE1(name)	MEMWRITE(name, Data);
	int _iLen = 0;
	short tmp_short;
	/*static int i = 0;*/		//< duan0603 i j k 为具有代码块作用域的静态（静态存储周期）变量，保证所有通道都被广播  duan20200616注释
	static int j = 0;
	static int k = 0;
	void* Data1 = NULL;
	Card_Base_t* base = NULL;

	//< 报头
	MEMWRITE1(Head);

	//< 站号
	tmp_short = Station_ID;
	MEMWRITE1(tmp_short);

	//< 第三个数据存放从下一个数据开始从后数多少个字节为报尾，用于对报文的报尾进行校验，此处先保留该存储位置，稍后再对其进行存储
	Data1 = Data;
	tmp_short = 0;
	MEMWRITE1(tmp_short);
	_iLen = (int)(_iLen - sizeof(tmp_short));

	//< 第四个数据存储本次要广播的通道数量，这个数据等打包完成后最后写入，此处先保留该存储位置，稍后再对其进行存储
	MEMWRITE1(SaveChannel_Num[0]);
	_iLen = (int)(_iLen - sizeof(SaveChannel_Num[0]));

	while ((BCDVIO_CARD_Count[0] < TYP_MAX_CARD) && (_iLen < Limit_Len))
	{
		if (BCDVIO_CARD_Count[0] == TYP_SAMAIO)
		{ 
			BCDVIO_CARD_Count[0] ++; continue;
		}
		while ((j < Card_List[BCDVIO_CARD_Count[0]].iCount) && (_iLen < Limit_Len))
		{
			base = (Card_Base_t*)SearchAt(((List_Base_t*)Card_List[BCDVIO_CARD_Count[0]].ppData[0]), j);
			if (base != NULL)
			{
				while ((k < (base->IO_Num.DI_Num + base->IO_Num.DO_Num)) && (_iLen < Limit_Len))
				{
					if (k < base->IO_Num.DI_Num)
						_iLen += BCDVIO(&(base->DIChannel[k]), &Data, SaveChannel_Num);
					else
						_iLen += BCDVIO(&(base->DOChannel[k - base->IO_Num.DI_Num]), &Data, SaveChannel_Num);
					k++;
				}
				if (k >= (base->IO_Num.DI_Num + base->IO_Num.DO_Num)) { k = 0; }
			}
			if (k == 0) { j++; }
		}
		if (j >= Card_List[BCDVIO_CARD_Count[0]].iCount) { j = 0; }
		if (j == 0) { BCDVIO_CARD_Count[0] ++; }
	}
	/*if (i >= TYP_MAX_CARD) { i = 0; }*/							//< duan20200616注释

	//< 写第三个数据
	tmp_short = (short)(_iLen - sizeof(Head) - sizeof(short) + sizeof(SaveChannel_Num[0]));//< 等于目前已经计数的长度减去报头，减去站号，加上要广播模块数量数据的长度
	MEMWRITE(tmp_short, Data1);

	//< 写第四个数据
	MEMWRITE(SaveChannel_Num[0], Data1);

	//< 报尾
	MEMWRITE1(Tail);
	return _iLen;
#undef MEMWRITE1
}


//************************************
// Method:    	tBCIO						广播硬点线程
// Programmer:  lww
// Time:		2019/2/16
// Returns:   	void *
// Parameter: 	void * arg
//************************************
void *tBCIO(void* arg)
{
#define PACK_MAXNUM	2048 
#define LIMIT_LEN	512 
#define PORT (BCIO_PORT + 3 * Station_ID)

	int sock;
	struct sockaddr_in NetA;
	struct sockaddr_in NetB;
	timer_t BCAVIO_Timer;
	struct timespec time;
	short Head = 7678;						//< 报头
	short Tail = 1424;						//< 报尾
	char Data2Send[PACK_MAXNUM];			//< 存放数据包的数组
	int _iLen = 0;
	short SaveChannel_Num = 0;				//< 当前数据包广播的测点数量
	pthread_t tBcDVIO_ID = 0;
	static int BCAVIO_CARD_Count = 0;		//< duan20200616
		//< duan20200610
	//< 初始化UDP设置
	printf("the Kernel_%s is %d\r\n", "tBCAVIO_ID", syscall(SYS_gettid));	
	if (false == UDP_Init(&sock, (uint16_t)PORT, 0, 0, UDP_SEND_STATUS, nullptr)) { return 0; }

	//< 设置发送到的IP地址及端口
	Addr_Set(&NetA, (uint16_t)PORT, inet_addr(NETA_IP_BC));
	Addr_Set(&NetB, (uint16_t)PORT, inet_addr(NETB_IP_BC));

	//< 设置广播周期
	MS2TimeSpec(&time, BCAVIO_PERIOD);

	//< 开启定时中断
	Timer_Create(&BCAVIO_Timer, BcAVIOSIG, &time);

	//< 开启广播数字量通道的线程
	THREAD_CREATE_FAILED(Thread_Create("tBcDVIO_ID", &tBcDVIO_ID, NULL, SCHED_POLICY, 89, true, tBCDVIO, CONTROL_CORE, NULL));

 
	while (1)
	{
		//< 等待信号量释放进行广播操作
		/*MUTEX_LOCK(BcAVIO_Mutex, "BcAVIO_Mutex lock failed");*/
		/*if (BCIO_flag)
		{
			BCIO_flag = false;
			BCIO_end = RealTime_Get();
			int aaa = Dt_Calu(BCIO_end, BCIO_begin);
			printf("BCIO delayTime is %d ms\n", aaa);
		}*/
		SEM_WAIT(BcAVIOSemId, "BcAVIOSemId wait failed");
		if (SYS_Role == Master_Alone_Role || SYS_Role == Master_Twins_Role)
		{
			while (BCAVIO_CARD_Count < TYP_MAX_CARD)
			{
				SaveChannel_Num = 0;
				//< 数据打包
				//if (BCIODataFlg)
				_iLen = BCAVIO_PACK_Make(Data2Send, Head, Tail, LIMIT_LEN, &SaveChannel_Num, &BCAVIO_CARD_Count);

				if (SaveChannel_Num > 0)
				{
					//< 发送数据
					UDP_Send(&sock, &NetA, (char*)Data2Send, _iLen); 
					UDP_Send(&sock, &NetB, (char*)Data2Send, _iLen); 
				}
			}
			if (BCAVIO_CARD_Count >= TYP_MAX_CARD)
				BCAVIO_CARD_Count = 0;
		}
	}
	close(sock);//< 断开连接
#undef LIMIT_LEN
#undef PACK_MAXNUM
#undef PORT
}


//************************************
// Method:    	tBCDVIO						广播数字量硬点线程
// Programmer:  lww
// Time:		2019/2/21
// Returns:   	void *
// Parameter: 	void * arg
//************************************
void *tBCDVIO(void* arg)
{
#define PACK_MAXNUM	2048 
#define LIMIT_LEN	512
#define PORT (BCIO_PORT + 1 + 3 * Station_ID)

	int sock;
	timer_t BCDVIO_Timer;
	struct timespec time;
	struct sockaddr_in NetA;
	struct sockaddr_in NetB;
	short Head = 7678;						//< 报头
	short Tail = 1424;						//< 报尾
	char Data2Send[PACK_MAXNUM];			//< 存放数据包的数组
	int _iLen = 0;
	short SaveChannel_Num = 0;				//< 当前数据包广播的测点数量
	static int BCDVIO_CARD_Count = 0;		//< duan20200616

	printf("the Kernel_%s is %d\r\n", "tBCDVIO_ID", syscall(SYS_gettid));			//< duan20200610
	//< 初始化UDP设置
	if (false == UDP_Init(&sock, (uint16_t)PORT, 0, 0, UDP_SEND_STATUS, nullptr)) { return 0; }

	//< 设置发送到的IP地址及端口
	Addr_Set(&NetA, (unsigned short)PORT, inet_addr(NETA_IP_BC));
	Addr_Set(&NetB, (unsigned short)PORT, inet_addr(NETB_IP_BC));

	//< 设置广播周期
	MS2TimeSpec(&time, BCDVIO_PERIOD);

	//< 开启定时中断
	Timer_Create(&BCDVIO_Timer, BcDVIOSIG, &time);

	while (1)
	{
		//< 等待信号量释放进行广播操作
		/*MUTEX_LOCK(BcDVIO_Mutex, "BcDVIO_Mutex lock failed");*/
		SEM_WAIT(BcDVIOSemId, "BcDVIOSemId wait failed");

		if (SYS_Role == Master_Alone_Role || SYS_Role == Master_Twins_Role)
		{
			while (BCDVIO_CARD_Count < TYP_MAX_CARD)
			{
				SaveChannel_Num = 0;
				//< 数据打包
				//if (BCIODataFlg)
				_iLen = BCDVIO_PACK_Make(Data2Send, Head, Tail, LIMIT_LEN, &SaveChannel_Num ,&BCDVIO_CARD_Count);

				if (SaveChannel_Num > 0)
				{
					//< 发送数据
					UDP_Send(&sock, &NetA, (char*)Data2Send, _iLen);
					UDP_Send(&sock, &NetB, (char*)Data2Send, _iLen);
				}
			}
			if (BCDVIO_CARD_Count >= TYP_MAX_CARD)
				BCDVIO_CARD_Count = 0;
			
		}
	}
	close(sock);//< 断开连接
#undef LIMIT_LEN
#undef PACK_MAXNUM
#undef PORT
}


